#include "game_byte.h"
#include "game_macros.h"
#include <iostream>
#include <vector>
#include <string>
#include <string.h>






void __readBytes(void* dest,const BYTE* from,size_t pos,size_t size){
  const BYTE *curr = from + pos;
  memcpy(dest, curr, size);
}

BYTE __readByte(const BYTE *buf, size_t pos)
{
  return buf[pos];
}

UINT8 __readUINT8(const BYTE *buf, size_t pos)
{
  return __readByte(buf, pos);
}

UINT16 __readUINT16(const BYTE *buf, size_t pos)
{
  UINT8 v1 = __readByte(buf, pos);
  UINT8 v2 = __readByte(buf, pos + 1);
  return v1 | (v2 << 8);
}

UINT32 __readUINT32(const BYTE *buf, size_t pos)
{
  UINT8 v1 = __readByte(buf, pos);
  UINT8 v2 = __readByte(buf, pos + 1);
  UINT8 v3 = __readByte(buf, pos + 2);
  UINT8 v4 = __readByte(buf, pos + 3);
  // return (v1 << 24) | (v2 << 16) | (v3 << 8) | v4;
  return v1 | (v2 << 8) | (v3 << 16) | (v4 << 24);
}

INT8 __readINT8(const BYTE *buf, size_t pos)
{
  UINT8 v = __readUINT8(buf, pos);

  if (v > 0x80)
  {
    return v - 0x100;
  }

  return v;
}
INT16 __readINT16(const BYTE *buf, size_t pos)
{
  UINT16 v = __readUINT16(buf, pos);

  if (v > 0x8000)
    return v - 0x10000;

  return v;
}
INT32 __readINT32(const BYTE *buf, size_t pos)
{
  UINT32 v = __readUINT32(buf, pos);

  if (v > 0x800000)
    return v - 0x1000000;

  return v;
}

void __readString(char* dest,const BYTE* from,size_t pos,size_t size){
  buff_t *ptr = (buff_t*)dest;
  __readBytes(ptr,from,pos,size);
}


UINT16 __readUINT16_BE(const BYTE *buf, size_t pos)
{
  UINT8 v1 = __readByte(buf, pos);
  UINT8 v2 = __readByte(buf, pos + 1);
  return (v1 << 8) | v2;
}

UINT32 __readUINT32_BE(const BYTE *buf, size_t pos)
{
  UINT8 v1 = __readByte(buf, pos);
  UINT8 v2 = __readByte(buf, pos + 1);
  UINT8 v3 = __readByte(buf, pos + 2);
  UINT8 v4 = __readByte(buf, pos + 3);
  return (v1 << 24) | (v2 << 16) | (v3 << 8) | v4;
}

INT16 __readINT16_BE(const BYTE *buf, size_t pos)
{
  UINT16 v = __readUINT16_BE(buf, pos);

  if (v > 0x8000)
    return v - 0x10000;

  return v;
}
INT32 __readINT32_BE(const BYTE *buf, size_t pos)
{
  UINT32 v = __readUINT32_BE(buf, pos);

  if (v > 0x800000)
    return v - 0x1000000;

  return v;
}

size_t __writeBytes(BYTE* dest,const void* from,size_t pos,size_t size){
  BYTE *curr = dest + pos;
  memcpy(curr, from, size);
  return size;
}

size_t __writeByte(BYTE *buf, size_t pos, BYTE v)
{
  buf[pos] = v;
  return 1;
}

size_t __writeUINT8(BYTE *buf, size_t pos, UINT8 v)
{
  return __writeByte(buf, pos, v);
}

size_t __writeUINT16(BYTE *buf, size_t pos, UINT16 v)
{
  __writeByte(buf, pos, v & 0xFF);
  __writeByte(buf, pos + 1, v >> 8);
  return 2;
}

size_t __writeUINT32(BYTE *buf, size_t pos, UINT32 v)
{
  __writeByte(buf, pos, v & 0xFFFFFF);
  __writeByte(buf, pos + 1, (v >> 8));
  __writeByte(buf, pos + 2, (v >> 16));
  __writeByte(buf, pos + 3, v >> 24);
  return 4;
}

size_t __writeUINT16_BE(BYTE *buf, size_t pos, UINT16 v)
{
  __writeByte(buf, pos, v >> 8);
  __writeByte(buf, pos + 1, v & 0xFF);

  return 2;
}

size_t __writeUINT32_BE(BYTE *buf, size_t pos, UINT32 v)
{
  __writeByte(buf, pos, v >> 24);
  __writeByte(buf, pos + 1, v >> 16);
  __writeByte(buf, pos + 2, v >> 8);
  __writeByte(buf, pos + 3, v & 0xFFFFFF);

  return 4;
}

size_t __writeINT8(BYTE *buf, size_t pos, INT8 v)
{
  return __writeByte(buf, pos, v);
}
size_t __writeINT16(BYTE *buf, size_t pos, INT16 v)
{
  if (v >= 0)
  {
    __writeByte(buf, pos, 0xff & v);
    __writeByte(buf, pos + 1, 0x7f & (v >> 8));
  }
  else
  {

    int i = 0x10000 + v;

    __writeByte(buf, pos, i & 0xff);
    __writeByte(buf, pos + 1, (i >> 8) & 0xff);
  }

  return 2;
}
size_t __writeINT32(BYTE *buf, size_t pos, INT32 v)
{
  if (v >= 0)
  {
    __writeByte(buf, pos, 0xff & v);
    __writeByte(buf, pos + 1, 0xff & (v >> 8));
    __writeByte(buf, pos + 2, 0xff & (v >> 16));
    __writeByte(buf, pos + 3, 0x7f & (v >> 24));
  }
  else
  {

    int i = 0x1000000 + v;

    __writeByte(buf, pos, i & 0xff);
    __writeByte(buf, pos + 1, (i >> 8) & 0xff);
    __writeByte(buf, pos + 2, (i >> 16) & 0xff);
    __writeByte(buf, pos + 3, (i >> 24) & 0xff);
  }

  return 4;
}

size_t __writeINT16_BE(BYTE *buf, size_t pos, INT16 v)
{
  if (v >= 0)
  {

    __writeByte(buf, pos, 0x7f & (v >> 8));
    __writeByte(buf, pos + 1, 0xff & v);
  }
  else
  {

    int i = 0x10000 + v;

    __writeByte(buf, pos, (i >> 8) & 0xff);
    __writeByte(buf, pos + 1, i & 0xff);
  }

  return 2;
}
size_t __writeINT32_BE(BYTE *buf, size_t pos, INT32 v)
{
  if (v >= 0)
  {

    __writeByte(buf, pos, 0x7f & (v >> 24));
    __writeByte(buf, pos + 1, 0xff & (v >> 16));
    __writeByte(buf, pos + 2, 0xff & (v >> 8));
    __writeByte(buf, pos + 3, 0xff & v);
  }
  else
  {

    int i = 0x1000000 + v;


    __writeByte(buf, pos, (i >> 24) & 0xff);
    __writeByte(buf, pos + 1, (i >> 16) & 0xff);
    __writeByte(buf, pos + 2, (i >> 8) & 0xff);
    __writeByte(buf, pos + 3, i & 0xff);
  }

  return 4;
}

void __bytes_from_hex(BYTE* dest, const char* value, size_t outSize)
{
  for (size_t i = 0; i < outSize; i++) {
    dest[i] = __byte_from_hex(&value[i*2]);
  }
}

void __bytes_to_hex(char* dest,const BYTE* value,size_t len){
  for(size_t i = 0;i < len;i++){
    __byte_to_hex(&dest[i * 2],value[i]);
  }

  dest[len * 2 + 1] = '\0';
}

void __byte_to_hex(char* dest,const BYTE value){
  // char* c1 = dest;
  // char* c2 = dest + 1;
  UINT8 v1 = value >> 4;
  UINT8 v2 = value & 0x0F;

  if(v1 > 9){
    v1 = 65 + v1 - 10;
  }else{
    v1 = 48 + v1;
  }

  if(v2 > 9){
    v2 = 65 + v2 - 10;
  }else{
    v2 = 48 + v2;
  }

  memset(dest,v1,1);
  memset(dest + 1,v2,1);
}

BYTE __byte_from_hex(const char* ptr){
  UINT8 c1 = ptr[0];
  UINT8 c2 = ptr[1];

  if(c1 >= 65){
    c1 -= 0x37;
  }else{
    c1 -= 0x30;
  }

  if(c2 >= 65){
    c2 -= 0x37;
  }else{
    c2 -= 0x30;
  }

  return (c1 << 4) | (c2 & 0xF);
}



CGameByteArray::CGameByteArray()
{
  _capacity = CGAME_BYTE_BUFF_MAX_LEN;
  _ptr = new buff_t[_capacity];
  _position = 0;
  _size = 0;
}

CGameByteArray::CGameByteArray(size_t capacity)
{
  _capacity = capacity;
  _ptr = new buff_t[_capacity];
  _position = 0;
  _size = 0;
}

CGameByteArray::CGameByteArray(buff_t *ptr, size_t size)
{
  _capacity = _size = size;
  _ptr = ptr;
  _position = 0;
  _pool = TRUE;
}

CGameByteArray::CGameByteArray(bytebuf_t &buf){
  //TODO
}

void CGameByteArray::setEndian(int v)
{
  this->_endian = v;
}

int CGameByteArray::getEndian() const
{
  return _endian;
}

size_t CGameByteArray::getSize() const
{
  return _size;
}

size_t CGameByteArray::getCapacity() const
{
  return _capacity;
}

size_t CGameByteArray::getPosition() const
{
  return _position;
}
size_t CGameByteArray::setPosition(size_t pos)
{
  _position = pos;
  return _position;
}

BOOL CGameByteArray::getPool() const
{
  return _pool;
}

CGameByteArray::~CGameByteArray()
{
}

size_t CGameByteArray::readBytes(void *dest, size_t len)
{
  if(_position + len > _size)
    return -1;

  __readBytes(dest,_ptr,_position,len);
  _position += len;
  return len;
}

size_t CGameByteArray::readString(char *dest)
{
  size_t p = _position;
  // size_t max = _size - _position;
  while (p < _size)
  {
    if (_ptr[p] == '\0')
    {

      size_t ret = p - _position;
      readBytes(dest, ret);
      _position = p;
      return ret;
    }

    p += 1;
  }

  return -1;
}

UINT8 CGameByteArray::readUINT8()
{
  C_ASSERT(_position + 1 <= _size, "overrange");
  UINT8 v = __readUINT8(_ptr, _position);
  _position += 1;
  return v;
}
UINT16 CGameByteArray::readUINT16()
{
  C_ASSERT(_position + 2 <= _size, "overrange");
  UINT16 v;
  if (BIG_ENDIAN == _endian)
  {
    v = __readUINT16_BE(_ptr, _position);
  }
  else
  {
    v = __readUINT16(_ptr, _position);
  }
  _position += 2;
  return v;
}
UINT32 CGameByteArray::readUINT32()
{
  C_ASSERT(_position + 4 <= _size, "overrange");
  UINT32 v;
  if (BIG_ENDIAN == _endian)
  {
    v = __readUINT32_BE(_ptr, _position);
  }
  else
  {
    v = __readUINT32(_ptr, _position);
  }
  _position += 4;
  return v;
}

INT8 CGameByteArray::readINT8()
{
  C_ASSERT(_position + 1 <= _size, "overrange");
  INT8 v = __readINT8(_ptr, _position);
  _position += 1;
  return v;
}
INT16 CGameByteArray::readINT16()
{
  C_ASSERT(_position + 2 <= _size, "overrange");
  INT16 v;
  if (BIG_ENDIAN == _endian)
  {
    v = __readINT16_BE(_ptr, _position);
  }
  else
  {
    v = __readINT16(_ptr, _position);
  }
  _position += 2;
  return v;
}
INT32 CGameByteArray::readINT32()
{
  C_ASSERT(_position + 4 <= _size, "overrange");
  INT32 v;
  if (BIG_ENDIAN == _endian)
  {
    v = __readINT32_BE(_ptr, _position);
  }
  else
  {
    v = __readINT32(_ptr, _position);
  }
  _position += 4;
  return v;
}

BOOL CGameByteArray::writeUINT8(UINT8 v)
{
  if(_position + 1 > _capacity)
    return FALSE;

  __writeByte(_ptr, _position, v);
  _position += 1;
  if (_position > _size)
    _size = _position;

  return TRUE;
}

BOOL CGameByteArray::writeUINT16(UINT16 v)
{
  if(_position + 2 > _capacity)
    return FALSE;

  if (BIG_ENDIAN == _endian)
  {
    __writeUINT16_BE(_ptr, _position, v);
  }
  else
  {
    __writeUINT16(_ptr, _position, v);
  }
  _position += 2;
  if (_position > _size)
    _size = _position;

  return TRUE;
}
BOOL CGameByteArray::writeUINT32(UINT32 v)
{
  if(_position + 4 > _capacity)
    return FALSE;

  if (BIG_ENDIAN == _endian)
  {
    __writeUINT32_BE(_ptr, _position, v);
  }
  else
  {
    __writeUINT32(_ptr, _position, v);
  }
  _position += 4;
  if (_position > _size)
    _size = _position;

  return TRUE;
}

BOOL CGameByteArray::writeINT8(INT8 v) {
  if(_position + 1 > _capacity)
    return FALSE;
  __writeINT8(_ptr,_position,v);
  _position += 1;
  if (_position > _size)
    _size = _position;
  return TRUE;
}
BOOL CGameByteArray::writeINT16(INT16 v) {

  if(_position + 2 > _capacity)
    return FALSE;

  if (BIG_ENDIAN == _endian)
  {
    __writeINT16_BE(_ptr,_position,v);
  }else{
    __writeINT16(_ptr,_position,v);
  }


  _position += 2;
  if (_position > _size)
    _size = _position;

  return TRUE;
}
BOOL CGameByteArray::writeINT32(INT32 v) {

  if(_position + 4 > _capacity)
    return FALSE;

  if (BIG_ENDIAN == _endian)
  {
    __writeINT32_BE(_ptr,_position,v);
  }else{
    __writeINT32(_ptr,_position,v);
  }


  _position += 4;
  if (_position > _size)
    _size = _position;

  return TRUE;
}

size_t CGameByteArray::writeBytes(const void* src,size_t len)
{
  if(_position + len > _capacity)
    return -1;

  __writeBytes(_ptr,src,_position,len);
  _position += len;
  if (_position > _size)
    _size = _position;

  return len;
}

void CGameByteArray::writeBytez(BYTE v,size_t size)
{
  for(size_t i = 0;i < size;i++){
    writeUINT8(v);
  }
}

size_t CGameByteArray::writeString(const char *src)
{
  size_t len = strlen(src);
  return writeString(src,len);
}
size_t CGameByteArray::writeString(const char *src, size_t len) {
  return writeBytes(src,len);
}

void CGameByteArray::reset(){
  _position = 0;
}

void CGameByteArray::clear(){
  _position = 0;
  _size = 0;
}

const BYTE *CGameByteArray::data() const
{
  return (const BYTE *)_ptr;
}
